#region copyright
/*
* Copyright (c) 2008, Dion Kurczek
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*     * Redistributions of source code must retain the above copyright
*       notice, this list of conditions and the following disclaimer.
*     * Redistributions in binary form must reproduce the above copyright
*       notice, this list of conditions and the following disclaimer in the
*       documentation and/or other materials provided with the distribution.
*     * Neither the name of the <organization> nor the
*       names of its contributors may be used to endorse or promote products
*       derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY DION KURCZEK ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL DION KURCZEK BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#endregion
using System;
using System.Collections.Generic;
using System.Text;
using System.Drawing;

namespace SCG.TurboSprite
{
    public class ShockWaveSprite : Sprite
    {
        //constructor
        public ShockWaveSprite(int waves, double radius, int lifeSpan, Color startColor, Color endColor)
        {
            _lifeSpan = lifeSpan;
            Shape = new RectangleF(-50, -50, 100, 100);
            _waveCount = waves;
            StartColor = startColor;
            EndColor = endColor;
            Radius = radius;
        }

        //decrease life span
        public override void Process()
        {
            _lifeSpan--;
            if (_lifeSpan <= 0)
                Kill();
        }

        //Render the sprite
        public override void Render(System.Drawing.Graphics g)
        {
            //create waves on demand
            if (_waves.Count == 0)
            {
                while (_waveCount > 0)
                {
                    Wave wave = new Wave();
                    wave.Color = Sprite.ColorFromRange(StartColor, EndColor);
                    wave.Radius = Radius;
                    if (ExpansionRateStart > 0 && ExpansionRateEnd > ExpansionRateStart)
                    {
                        double range = ExpansionRateEnd - ExpansionRateStart;
                        wave.ExpansionRate = range * Sprite.RND.NextDouble() + ExpansionRateStart;
                    }
                    _waves.Add(wave);
                    if (Filled)
                        wave.FillColor = Sprite.ColorFromRange(FillColorStart, FillColorEnd);
                    _waveCount--;
                }
            }
            Pen pen = new Pen(Color.Black);
            Brush brush;
            foreach (Wave wave in _waves)
            {
                int newAlpha = wave.alpha - Sprite.RND.Next(10);
                if (newAlpha < 0)
                    newAlpha = 0;
                wave.alpha = (byte)newAlpha;
                wave.Color = Color.FromArgb(newAlpha, wave.Color);
                wave.Radius += wave.ExpansionRate;
                int w = (int)(wave.Radius * 2 + Sprite.RND.Next(_jitter) - _jitterHalf);
                int h = (int)(wave.Radius * 2 + Sprite.RND.Next(_jitter) - _jitterHalf);
                int x = (int)(X - wave.Radius + Sprite.RND.Next(_jitter) - _jitterHalf);
                int y = (int)(Y - wave.Radius + Sprite.RND.Next(_jitter) - _jitterHalf);
                if (Filled)
                {
                    brush = new SolidBrush(wave.FillColor);
                    g.FillEllipse(brush, x - Surface.OffsetX, y - Surface.OffsetY, w, h);
                }
                pen.Color = wave.Color;
                pen.Width = LineWidth;
                g.DrawEllipse(pen, x - Surface.OffsetX, y - Surface.OffsetY, w, h);
            }
        }

        //Radius
        public double Radius { get; set; }

        //Width of the drawing pen
        public int LineWidth
        {
            get
            {
                return _width;
            }
            set
            {
                _width = value;
            }
        }

        //Jittering
        public int Jitters
        {
            get
            {
                return _jitter;
            }
            set
            {
                if (value >= 0)
                {
                    _jitter = value;
                    _jitterHalf = value / 2;
                }
            }
        }

        //Start and end colors
        public Color StartColor { get; set; }

        public Color EndColor { get; set; }

        //Expansion rate
        public double ExpansionRateStart { get; set; }

        public double ExpansionRateEnd { get; set; }

        //Should the shockwaves be filled?
        public bool Filled { get; set; }

        //Color range that shockwaves should be filled
        public Color FillColorStart
        {
            get
            {
                return _fillStart;
            }
            set
            {
                _fillStart = value;
            }
        }
        public Color FillColorEnd
        {
            get
            {
                return _fillEnd;
            }
            set
            {
                _fillEnd = value;
            }
        }

        //private members
        private List<Wave> _waves = new List<Wave>();
        private int _lifeSpan;
        private Color _fillStart = Color.Beige;
        private Color _fillEnd = Color.Yellow;
        private int _waveCount;
        private int _width = 1;
        private int _jitter = 6;
        private int _jitterHalf = 3;
    }

    internal class Wave
    {
        internal double ExpansionRate = Sprite.RND.NextDouble() * Sprite.RND.NextDouble() * Sprite.RND.NextDouble() * 6.0d;
        internal Color Color;
        internal double Radius;
        internal Color FillColor = Color.Transparent;
        internal byte alpha = 255;
    }
}
